package com.evil.application.pojo.dto.form.control;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import com.evil.common.application.enums.form.control.ControlValueNumberEnum;
import com.evil.common.application.enums.judge.JudgeSignEnum;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * 控件公式 实体
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Data
public class ControlJudgeFormulaDTO {

    private final ControlValueNumberEnum valueNumberEnum;

    private final Map<JudgeSignEnum, BiFunction<List<String>, List<String>, Boolean>> judgeSigns;

    public ControlJudgeFormulaDTO() {
        this.valueNumberEnum = ControlValueNumberEnum.SINGLE;
        this.judgeSigns = new LinkedHashMap<>();
    }

    public ControlJudgeFormulaDTO(ControlValueNumberEnum valueNumberEnum) {
        this.valueNumberEnum = valueNumberEnum;
        this.judgeSigns = new LinkedHashMap<>();
    }

    public ControlJudgeFormulaDTO put(JudgeSignEnum judgeSignEnum, BiFunction<List<String>, List<String>, Boolean> judgeSign) {
        this.judgeSigns.put(judgeSignEnum, judgeSign);
        return this;
    }

    public List<ControlJudgeSignRespDTO> getAll() {
        return this.judgeSigns.keySet().stream().map(ControlJudgeSignRespDTO::new).collect(Collectors.toList());
    }

    /**
     * 条件判断
     *
     * @param judgeSignEnum judgeSignEnum
     * @param key           当前值
     * @param value         条件值
     * @return Boolean
     */
    public Boolean applyJudgeSigns(JudgeSignEnum judgeSignEnum, List<String> key, List<String> value) {
        if (this.containsKey(judgeSignEnum)) {
            return this.judgeSigns.get(judgeSignEnum).apply(key, value);
        }
        return false;
    }

    public boolean containsKey(JudgeSignEnum judgeSignEnum) {
        return this.judgeSigns.containsKey(judgeSignEnum);
    }

    /**
     * 添加【相等】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addEquals() {
        this.judgeSigns.put(JudgeSignEnum.EQUALS, this::equalsFormula);
        return this;
    }

    /**
     * 添加【不相等】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addUnEquals() {
        this.judgeSigns.put(JudgeSignEnum.UN_EQUALS, (key, value) -> !this.equalsFormula(key, value));
        return this;
    }

    /**
     * 添加【包含】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addContain() {
        this.judgeSigns.put(JudgeSignEnum.CONTAIN, this::containFormula);
        return this;
    }

    /**
     * 添加【包含】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addUnContain() {
//        this.judgeSigns.put(JudgeSignEnum.UN_CONTAIN, pair -> !this.containFormula(pair));
        return this;
    }

    /**
     * 添加【小于等于】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addLt() {
        this.judgeSigns.put(JudgeSignEnum.LT, (key, value) -> this.compare(key, value, NumberUtil::isLess));
        return this;
    }

    /**
     * 添加【小于等于】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addLte() {
        this.judgeSigns.put(JudgeSignEnum.LTE, (key, value) -> this.compare(key, value, NumberUtil::isLessOrEqual));
        return this;
    }

    /**
     * 添加【大于等于】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addGt() {
        this.judgeSigns.put(JudgeSignEnum.GT, (key, value) -> this.compare(key, value, NumberUtil::isGreater));
        return this;
    }

    /**
     * 添加【大于等于】公式
     *
     * @return ControlJudgeFormulaDTO
     */
    public ControlJudgeFormulaDTO addGte() {
        this.judgeSigns.put(JudgeSignEnum.GTE, (key, value) -> this.compare(key, value, NumberUtil::isGreaterOrEqual));
        return this;
    }

    private Boolean equalsFormula(List<String> key, List<String> value) {
        if (value.isEmpty()) {
            // 判断是否为空
            return key.stream().anyMatch(StringUtils::isBlank);
        }
        key.sort(Comparator.comparing(String::hashCode));
        value.sort(Comparator.comparing(String::hashCode));

        return key.toString().equals(value.toString());
    }

    /**
     * 当前值中 是否包含 条件值
     *
     * @param key   当前值
     * @param value 条件值
     * @return Boolean
     */
    private Boolean containFormula(List<String> key, List<String> value) {
        // 单个值
        if (ControlValueNumberEnum.SINGLE == valueNumberEnum) {
            // 首个元素字符包含
            return key.stream().findFirst()
                    // 当前值字符串中 是否包含 条件值字符串
                    .map(k -> value.stream().findFirst().map(k::contains).orElse(false))
                    // 如果 当前值为空 则判断 条件值 是否也为空
                    .orElse(value.isEmpty());
        }
        // 多个值
        else {
            // 任意元素通过全串匹配
            return key.stream().anyMatch(value::contains);
        }
    }

    /**
     * 当前值(第一个值) 比较 条件值(第一个值)
     *
     * @param key   当前值
     * @param value 条件值
     * @return Boolean
     */
    private Boolean compare(List<String> key, List<String> value, BiFunction<BigDecimal, BigDecimal, Boolean> compare) {
        if (CollectionUtil.isEmpty(key) || key.size() != 1 || CollectionUtil.isEmpty(value) || value.size() != 1) {
            return false;
        }
        try {
            return compare.apply(new BigDecimal(key.get(0)), new BigDecimal(value.get(0)));
        } catch (Exception e) {
            return false;
        }
    }
}
